package com.bytebuddytest.fieldandmethod;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.FieldManifestation;
import net.bytebuddy.description.modifier.MethodManifestation;
import net.bytebuddy.description.modifier.Ownership;
import net.bytebuddy.description.modifier.SynchronizationState;
import net.bytebuddy.description.modifier.SyntheticState;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.pool.TypePool;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author yutianhong
 * @version 1.0
 * @since 2023/09/25 20:10
 */
public class DefineMethodAndFieldTest {
    @Test
    public void testDefineMethod() throws Exception {
        Class<? extends Foo> loaded = new ByteBuddy()
                .subclass(Foo.class)
                .defineMethod("qux", String.class,
                        Visibility.PUBLIC, Ownership.MEMBER, SynchronizationState.PLAIN, SyntheticState.PLAIN)
                .withParameter(String.class, "name", MethodManifestation.FINAL.getMask())
                .intercept(FixedValue.value("hello"))
                .make()
                .load(getClass().getClassLoader())
                .getLoaded();
        Method qux = loaded.getDeclaredMethod("qux", String.class);
        Object ret = qux.invoke(loaded.newInstance(), "a");
        Assert.assertEquals(ret, "hello");
    }


    @Test
    public void testDefineField() throws NoSuchFieldException {
        Class<?> newFoo = new ByteBuddy()
                .subclass(TypePool.Default.ofSystemLoader().describe("com.bytebuddytest.fieldandmethod.Foo").resolve())
                .defineField("name", String.class, Visibility.PUBLIC, Ownership.MEMBER, FieldManifestation.VOLATILE)
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                .getLoaded();

        Field name = newFoo.getDeclaredField("name");
        Assert.assertEquals(name.getType(), String.class);
        Assert.assertNotSame(name.getModifiers() & Modifier.VOLATILE, 0);
    }

}
